home *** CD-ROM | disk | FTP | other *** search
/ Linux Cubed Series 3: Developer Tools / Linux Cubed Series 3 - Developer Tools.iso / devel / lang / lisp / stk-3.002 / stk-3 / STk-3.1 / Tk / generic / tkXEvent.c < prev    next >
Encoding:
C/C++ Source or Header  |  1995-12-04  |  20.4 KB  |  723 lines

  1. /* 
  2.  * tkXEvent.c --
  3.  *
  4.  *    This file provides basic low-level facilities for managing
  5.  *    X events.  It builds on the facilities provided in tkEvent.c.
  6.  *
  7.  * Copyright (c) 1990-1994 The Regents of the University of California.
  8.  * Copyright (c) 1994 Sun Microsystems, Inc.
  9.  *
  10.  * See the file "license.terms" for information on usage and redistribution
  11.  * of this file, and for a DISCLAIMER OF ALL WARRANTIES.
  12.  */
  13.  
  14. static char sccsid[] = "@(#) tkXEvent.c 1.9 95/06/23 10:41:40";
  15.  
  16. #include "tkPort.h"
  17. #include "tkInt.h"
  18. #include <signal.h>
  19.  
  20. /*
  21.  * There's a potential problem if a handler is deleted while it's
  22.  * current (i.e. its procedure is executing), since Tk_HandleEvent
  23.  * will need to read the handler's "nextPtr" field when the procedure
  24.  * returns.  To handle this problem, structures of the type below
  25.  * indicate the next handler to be processed for any (recursively
  26.  * nested) dispatches in progress.  The nextHandler fields get
  27.  * updated if the handlers pointed to are deleted.  Tk_HandleEvent
  28.  * also needs to know if the entire window gets deleted;  the winPtr
  29.  * field is set to zero if that particular window gets deleted.
  30.  */
  31.  
  32. typedef struct InProgress {
  33.     XEvent *eventPtr;         /* Event currently being handled. */
  34.     TkWindow *winPtr;         /* Window for event.  Gets set to None if
  35.                   * window is deleted while event is being
  36.                   * handled. */
  37.     TkEventHandler *nextHandler; /* Next handler in search. */
  38.     struct InProgress *nextPtr;     /* Next higher nested search. */
  39. } InProgress;
  40.  
  41. static InProgress *pendingPtr = NULL;
  42.                 /* Topmost search in progress, or
  43.                  * NULL if none. */
  44.  
  45. /*
  46.  * For each call to Tk_CreateGenericHandler, an instance of the following
  47.  * structure will be created.  All of the active handlers are linked into a
  48.  * list.
  49.  */
  50.  
  51. typedef struct GenericHandler {
  52.     Tk_GenericProc *proc;    /* Procedure to dispatch on all X events. */
  53.     ClientData clientData;    /* Client data to pass to procedure. */
  54.     int deleteFlag;        /* Flag to set when this handler is deleted. */
  55.     struct GenericHandler *nextPtr;
  56.                 /* Next handler in list of all generic
  57.                  * handlers, or NULL for end of list. */
  58. } GenericHandler;
  59.  
  60. static GenericHandler *genericList = NULL;
  61.                 /* First handler in the list, or NULL. */
  62. static GenericHandler *lastGenericPtr = NULL;
  63.                 /* Last handler in list. */
  64.  
  65. /*
  66.  * There's a potential problem if Tk_HandleEvent is entered recursively.
  67.  * A handler cannot be deleted physically until we have returned from
  68.  * calling it.  Otherwise, we're looking at unallocated memory in advancing to
  69.  * its `next' entry.  We deal with the problem by using the `delete flag' and
  70.  * deleting handlers only when it's known that there's no handler active.
  71.  *
  72.  * The following variable has a non-zero value when a handler is active.
  73.  */
  74.  
  75. static int genericHandlersActive = 0;
  76.  
  77. /*
  78.  * Array of event masks corresponding to each X event:
  79.  */
  80.  
  81. static unsigned long eventMasks[] = {
  82.     0,
  83.     0,
  84.     KeyPressMask,            /* KeyPress */
  85.     KeyReleaseMask,            /* KeyRelease */
  86.     ButtonPressMask,            /* ButtonPress */
  87.     ButtonReleaseMask,            /* ButtonRelease */
  88.     PointerMotionMask|PointerMotionHintMask|ButtonMotionMask
  89.         |Button1MotionMask|Button2MotionMask|Button3MotionMask
  90.         |Button4MotionMask|Button5MotionMask,
  91.                     /* MotionNotify */
  92.     EnterWindowMask,            /* EnterNotify */
  93.     LeaveWindowMask,            /* LeaveNotify */
  94.     FocusChangeMask,            /* FocusIn */
  95.     FocusChangeMask,            /* FocusOut */
  96.     KeymapStateMask,            /* KeymapNotify */
  97.     ExposureMask,            /* Expose */
  98.     ExposureMask,            /* GraphicsExpose */
  99.     ExposureMask,            /* NoExpose */
  100.     VisibilityChangeMask,        /* VisibilityNotify */
  101.     SubstructureNotifyMask,        /* CreateNotify */
  102.     StructureNotifyMask,        /* DestroyNotify */
  103.     StructureNotifyMask,        /* UnmapNotify */
  104.     StructureNotifyMask,        /* MapNotify */
  105.     SubstructureRedirectMask,        /* MapRequest */
  106.     StructureNotifyMask,        /* ReparentNotify */
  107.     StructureNotifyMask,        /* ConfigureNotify */
  108.     SubstructureRedirectMask,        /* ConfigureRequest */
  109.     StructureNotifyMask,        /* GravityNotify */
  110.     ResizeRedirectMask,            /* ResizeRequest */
  111.     StructureNotifyMask,        /* CirculateNotify */
  112.     SubstructureRedirectMask,        /* CirculateRequest */
  113.     PropertyChangeMask,            /* PropertyNotify */
  114.     0,                    /* SelectionClear */
  115.     0,                    /* SelectionRequest */
  116.     0,                    /* SelectionNotify */
  117.     ColormapChangeMask,            /* ColormapNotify */
  118.     0,                    /* ClientMessage */
  119.     0,                    /* Mapping Notify */
  120. };
  121.  
  122. /*
  123.  *--------------------------------------------------------------
  124.  *
  125.  * Tk_CreateEventHandler --
  126.  *
  127.  *    Arrange for a given procedure to be invoked whenever
  128.  *    events from a given class occur in a given window.
  129.  *
  130.  * Results:
  131.  *    None.
  132.  *
  133.  * Side effects:
  134.  *    From now on, whenever an event of the type given by
  135.  *    mask occurs for token and is processed by Tk_HandleEvent,
  136.  *    proc will be called.  See the manual entry for details
  137.  *    of the calling sequence and return value for proc.
  138.  *
  139.  *--------------------------------------------------------------
  140.  */
  141.  
  142. void
  143. Tk_CreateEventHandler(token, mask, proc, clientData)
  144.     Tk_Window token;        /* Token for window in which to
  145.                  * create handler. */
  146.     unsigned long mask;        /* Events for which proc should
  147.                  * be called. */
  148.     Tk_EventProc *proc;        /* Procedure to call for each
  149.                  * selected event */
  150.     ClientData clientData;    /* Arbitrary data to pass to proc. */
  151. {
  152.     register TkEventHandler *handlerPtr;
  153.     register TkWindow *winPtr = (TkWindow *) token;
  154.     int found;
  155.  
  156.     /*
  157.      * Skim through the list of existing handlers to (a) compute the
  158.      * overall event mask for the window (so we can pass this new
  159.      * value to the X system) and (b) see if there's already a handler
  160.      * declared with the same callback and clientData (if so, just
  161.      * change the mask).  If no existing handler matches, then create
  162.      * a new handler.
  163.      */
  164.  
  165.     found = 0;
  166.     if (winPtr->handlerList == NULL) {
  167.     handlerPtr = (TkEventHandler *) ckalloc(
  168.         (unsigned) sizeof(TkEventHandler));
  169.     winPtr->handlerList = handlerPtr;
  170.     goto initHandler;
  171.     } else {
  172.     for (handlerPtr = winPtr->handlerList; ;
  173.         handlerPtr = handlerPtr->nextPtr) {
  174.         if ((handlerPtr->proc == proc)
  175.             && (handlerPtr->clientData == clientData)) {
  176.         handlerPtr->mask = mask;
  177.         found = 1;
  178.         }
  179.         if (handlerPtr->nextPtr == NULL) {
  180.         break;
  181.         }
  182.     }
  183.     }
  184.  
  185.     /*
  186.      * Create a new handler if no matching old handler was found.
  187.      */
  188.  
  189.     if (!found) {
  190.     handlerPtr->nextPtr = (TkEventHandler *)
  191.         ckalloc(sizeof(TkEventHandler));
  192.     handlerPtr = handlerPtr->nextPtr;
  193.     initHandler:
  194.     handlerPtr->mask = mask;
  195.     handlerPtr->proc = proc;
  196.     handlerPtr->clientData = clientData;
  197.     handlerPtr->nextPtr = NULL;
  198.     }
  199.  
  200.     /*
  201.      * No need to call XSelectInput:  Tk always selects on all events
  202.      * for all windows (needed to support bindings on classes and "all").
  203.      */
  204. }
  205.  
  206. /*
  207.  *--------------------------------------------------------------
  208.  *
  209.  * Tk_DeleteEventHandler --
  210.  *
  211.  *    Delete a previously-created handler.
  212.  *
  213.  * Results:
  214.  *    None.
  215.  *
  216.  * Side effects:
  217.  *    If there existed a handler as described by the
  218.  *    parameters, the handler is deleted so that proc
  219.  *    will not be invoked again.
  220.  *
  221.  *--------------------------------------------------------------
  222.  */
  223.  
  224. void
  225. Tk_DeleteEventHandler(token, mask, proc, clientData)
  226.     Tk_Window token;        /* Same as corresponding arguments passed */
  227.     unsigned long mask;        /* previously to Tk_CreateEventHandler. */
  228.     Tk_EventProc *proc;
  229.     ClientData clientData;
  230. {
  231.     register TkEventHandler *handlerPtr;
  232.     register InProgress *ipPtr;
  233.     TkEventHandler *prevPtr;
  234.     register TkWindow *winPtr = (TkWindow *) token;
  235.  
  236.     /*
  237.      * Find the event handler to be deleted, or return
  238.      * immediately if it doesn't exist.
  239.      */
  240.  
  241.     for (handlerPtr = winPtr->handlerList, prevPtr = NULL; ;
  242.         prevPtr = handlerPtr, handlerPtr = handlerPtr->nextPtr) {
  243.     if (handlerPtr == NULL) {
  244.         return;
  245.     }
  246.     if ((handlerPtr->mask == mask) && (handlerPtr->proc == proc)
  247.         && (handlerPtr->clientData == clientData)) {
  248.         break;
  249.     }
  250.     }
  251.  
  252.     /*
  253.      * If Tk_HandleEvent is about to process this handler, tell it to
  254.      * process the next one instead.
  255.      */
  256.  
  257.     for (ipPtr = pendingPtr; ipPtr != NULL; ipPtr = ipPtr->nextPtr) {
  258.     if (ipPtr->nextHandler == handlerPtr) {
  259.         ipPtr->nextHandler = handlerPtr->nextPtr;
  260.     }
  261.     }
  262.  
  263.     /*
  264.      * Free resources associated with the handler.
  265.      */
  266.  
  267.     if (prevPtr == NULL) {
  268.     winPtr->handlerList = handlerPtr->nextPtr;
  269.     } else {
  270.     prevPtr->nextPtr = handlerPtr->nextPtr;
  271.     }
  272.     ckfree((char *) handlerPtr);
  273.  
  274.  
  275.     /*
  276.      * No need to call XSelectInput:  Tk always selects on all events
  277.      * for all windows (needed to support bindings on classes and "all").
  278.      */
  279. }
  280.  
  281. /*--------------------------------------------------------------
  282.  *
  283.  * Tk_CreateGenericHandler --
  284.  *
  285.  *    Register a procedure to be called on each X event, regardless
  286.  *    of display or window.  Generic handlers are useful for capturing
  287.  *    events that aren't associated with windows, or events for windows
  288.  *    not managed by Tk.
  289.  *
  290.  * Results:
  291.  *    None.
  292.  *
  293.  * Side Effects:
  294.  *    From now on, whenever an X event is given to Tk_HandleEvent,
  295.  *    invoke proc, giving it clientData and the event as arguments.
  296.  *
  297.  *--------------------------------------------------------------
  298.  */
  299.  
  300. void
  301. Tk_CreateGenericHandler(proc, clientData)
  302.      Tk_GenericProc *proc;    /* Procedure to call on every event. */
  303.      ClientData clientData;    /* One-word value to pass to proc. */
  304. {
  305.     GenericHandler *handlerPtr;
  306.     
  307.     handlerPtr = (GenericHandler *) ckalloc (sizeof (GenericHandler));
  308.     
  309.     handlerPtr->proc = proc;
  310.     handlerPtr->clientData = clientData;
  311.     handlerPtr->deleteFlag = 0;
  312.     handlerPtr->nextPtr = NULL;
  313.     if (genericList == NULL) {
  314.     genericList = handlerPtr;
  315.     } else {
  316.     lastGenericPtr->nextPtr = handlerPtr;
  317.     }
  318.     lastGenericPtr = handlerPtr;
  319. }
  320.  
  321. /*
  322.  *--------------------------------------------------------------
  323.  *
  324.  * Tk_DeleteGenericHandler --
  325.  *
  326.  *    Delete a previously-created generic handler.
  327.  *
  328.  * Results:
  329.  *    None.
  330.  *
  331.  * Side Effects:
  332.  *    If there existed a handler as described by the parameters,
  333.  *    that handler is logically deleted so that proc will not be
  334.  *    invoked again.  The physical deletion happens in the event
  335.  *    loop in Tk_HandleEvent.
  336.  *
  337.  *--------------------------------------------------------------
  338.  */
  339.  
  340. void
  341. Tk_DeleteGenericHandler(proc, clientData)
  342.      Tk_GenericProc *proc;
  343.      ClientData clientData;
  344. {
  345.     GenericHandler * handler;
  346.     
  347.     for (handler = genericList; handler; handler = handler->nextPtr) {
  348.     if ((handler->proc == proc) && (handler->clientData == clientData)) {
  349.         handler->deleteFlag = 1;
  350.     }
  351.     }
  352. }
  353.  
  354. /*
  355.  *--------------------------------------------------------------
  356.  *
  357.  * Tk_HandleEvent --
  358.  *
  359.  *    Given an event, invoke all the handlers that have
  360.  *    been registered for the event.
  361.  *
  362.  * Results:
  363.  *    None.
  364.  *
  365.  * Side effects:
  366.  *    Depends on the handlers.
  367.  *
  368.  *--------------------------------------------------------------
  369.  */
  370.  
  371. void
  372. Tk_HandleEvent(eventPtr)
  373.     XEvent *eventPtr;        /* Event to dispatch. */
  374. {
  375.     register TkEventHandler *handlerPtr;
  376.     register GenericHandler *genericPtr;
  377.     register GenericHandler *genPrevPtr;
  378.     TkWindow *winPtr;
  379.     unsigned long mask;
  380.     InProgress ip;
  381.     Window handlerWindow;
  382.     TkDisplay *dispPtr;
  383.  
  384.     /*
  385.      * First off, look for a special trigger event left around by the
  386.      * grab module.  If it's found, call the grab module and discard
  387.      * the event.
  388.      */
  389.  
  390.     if (eventPtr->xany.type == -1) {
  391.     TkGrabTriggerProc(eventPtr);
  392.     return;
  393.     }
  394.  
  395.     /* 
  396.      * Next, invoke all the generic event handlers (those that are
  397.      * invoked for all events).  If a generic event handler reports that
  398.      * an event is fully processed, go no further.
  399.      */
  400.  
  401.     for (genPrevPtr = NULL, genericPtr = genericList;  genericPtr != NULL; ) {
  402.     if (genericPtr->deleteFlag) {
  403.         if (!genericHandlersActive) {
  404.         GenericHandler *tmpPtr;
  405.  
  406.         /*
  407.          * This handler needs to be deleted and there are no
  408.          * calls pending through the handler, so now is a safe
  409.          * time to delete it.
  410.          */
  411.  
  412.         tmpPtr = genericPtr->nextPtr;
  413.         if (genPrevPtr == NULL) {
  414.             genericList = tmpPtr;
  415.         } else {
  416.             genPrevPtr->nextPtr = tmpPtr;
  417.         }
  418.         if (tmpPtr == NULL) {
  419.             lastGenericPtr = genPrevPtr;
  420.         }
  421.         (void) ckfree((char *) genericPtr);
  422.         genericPtr = tmpPtr;
  423.         continue;
  424.         }
  425.     } else {
  426.         int done;
  427.  
  428.         genericHandlersActive++;
  429.         done = (*genericPtr->proc)(genericPtr->clientData, eventPtr);
  430.         genericHandlersActive--;
  431.         if (done) {
  432.         return;
  433.         }
  434.     }
  435.     genPrevPtr = genericPtr;
  436.     genericPtr = genPrevPtr->nextPtr;
  437.     }
  438.  
  439.     /*
  440.      * If the event is a MappingNotify event, find its display and
  441.      * refresh the keyboard mapping information for the display.
  442.      * After that there's nothing else to do with the event, so just
  443.      * quit.
  444.      */
  445.  
  446.     if (eventPtr->type == MappingNotify) {
  447.     dispPtr = TkGetDisplay(eventPtr->xmapping.display);
  448.     if (dispPtr != NULL) {
  449.         XRefreshKeyboardMapping(&eventPtr->xmapping);
  450.         dispPtr->bindInfoStale = 1;
  451.     }
  452.     return;
  453.     }
  454.  
  455.     /*
  456.      * Events selected by StructureNotify require special handling.
  457.      * They look the same as those selected by SubstructureNotify.
  458.      * The only difference is whether the "event" and "window" fields
  459.      * are the same.  Compare the two fields and convert StructureNotify
  460.      * to SubstructureNotify if necessary.
  461.      */
  462.  
  463.     handlerWindow = eventPtr->xany.window;
  464.     mask = eventMasks[eventPtr->xany.type];
  465.     if (mask == StructureNotifyMask) {
  466.     if (eventPtr->xmap.event != eventPtr->xmap.window) {
  467.         mask = SubstructureNotifyMask;
  468.         handlerWindow = eventPtr->xmap.event;
  469.     }
  470.     }
  471.     winPtr = (TkWindow *) Tk_IdToWindow(eventPtr->xany.display, handlerWindow);
  472.     if (winPtr == NULL) {
  473.  
  474.     /*
  475.      * There isn't a TkWindow structure for this window.
  476.      * However, if the event is a PropertyNotify event then call
  477.      * the selection manager (it deals beneath-the-table with
  478.      * certain properties).
  479.      */
  480.  
  481.     if (eventPtr->type == PropertyNotify) {
  482.         TkSelPropProc(eventPtr);
  483.     }
  484.     return;
  485.     }
  486.  
  487.     if (winPtr->mainPtr != NULL) {
  488.     /*
  489.      * Call focus-related code to look at FocusIn, FocusOut, Enter,
  490.      * and Leave events;  depending on its return value, ignore the
  491.      * event.
  492.      */
  493.     
  494.     if ((mask & (FocusChangeMask|EnterWindowMask|LeaveWindowMask))
  495.         && !TkFocusFilterEvent(winPtr, eventPtr)) {
  496.         return;
  497.     }
  498.     
  499.     /*
  500.      * Redirect KeyPress and KeyRelease events to the focus window,
  501.      * or ignore them entirely if there is no focus window.  Map the
  502.      * x and y coordinates to make sense in the context of the focus
  503.      * window, if possible (make both -1 if the map-from and map-to
  504.      * windows don't share the same screen).
  505.      */
  506.     
  507.     if (mask & (KeyPressMask|KeyReleaseMask)) {
  508.         TkWindow *focusPtr;
  509.         int winX, winY, focusX, focusY;
  510.     
  511.         winPtr->dispPtr->lastEventTime = eventPtr->xkey.time;
  512.         focusPtr = TkGetFocus(winPtr);
  513.         if (focusPtr == NULL) {
  514.         return;
  515.         }
  516.         if ((focusPtr->display != winPtr->display)
  517.             || (focusPtr->screenNum != winPtr->screenNum)) {
  518.         eventPtr->xkey.x = -1;
  519.         eventPtr->xkey.y = -1;
  520.         } else {
  521.         Tk_GetRootCoords((Tk_Window) winPtr, &winX, &winY);
  522.         Tk_GetRootCoords((Tk_Window) focusPtr, &focusX, &focusY);
  523.         eventPtr->xkey.x -= focusX - winX;
  524.         eventPtr->xkey.y -= focusY - winY;
  525.         }
  526.         eventPtr->xkey.window = focusPtr->window;
  527.         winPtr = focusPtr;
  528.     }
  529.     
  530.     /*
  531.      * Call a grab-related procedure to do special processing on
  532.      * pointer events.
  533.      */
  534.     
  535.     if (mask & (ButtonPressMask|ButtonReleaseMask|PointerMotionMask
  536.         |EnterWindowMask|LeaveWindowMask)) {
  537.         if (mask & (ButtonPressMask|ButtonReleaseMask)) {
  538.         winPtr->dispPtr->lastEventTime = eventPtr->xbutton.time;
  539.         } else if (mask & PointerMotionMask) {
  540.         winPtr->dispPtr->lastEventTime = eventPtr->xmotion.time;
  541.         } else {
  542.         winPtr->dispPtr->lastEventTime = eventPtr->xcrossing.time;
  543.         }
  544.         if (TkPointerEvent(eventPtr, winPtr) == 0) {
  545.         return;
  546.         }
  547.     }
  548.     }
  549.  
  550. #ifdef TK_USE_INPUT_METHODS
  551.     /*
  552.      * Pass the event to the input method(s), if there are any, and
  553.      * discard the event if the input method(s) insist.  Create the
  554.      * input context for the window if it hasn't already been done
  555.      * (XFilterEvent needs this context).
  556.      */
  557.  
  558.     if (!(winPtr->flags & TK_CHECKED_IC)) {
  559.     if (winPtr->dispPtr->inputMethod != NULL) {
  560.         winPtr->inputContext = XCreateIC(
  561.             winPtr->dispPtr->inputMethod, XNInputStyle,
  562.             XIMPreeditNothing|XIMStatusNothing,
  563.             XNClientWindow, winPtr->window,
  564.             XNFocusWindow, winPtr->window, NULL);
  565.     }
  566.     winPtr->flags |= TK_CHECKED_IC;
  567.     }
  568.     if (XFilterEvent(eventPtr, None)) {
  569.         return;
  570.     }
  571. #endif /* TK_USE_INPUT_METHODS */
  572.  
  573.     /*
  574.      * For events where it hasn't already been done, update the current
  575.      * time in the display.
  576.      */
  577.  
  578.     if (eventPtr->type == PropertyNotify) {
  579.     winPtr->dispPtr->lastEventTime = eventPtr->xproperty.time;
  580.     }
  581.  
  582.     /*
  583.      * There's a potential interaction here with Tk_DeleteEventHandler.
  584.      * Read the documentation for pendingPtr.
  585.      */
  586.  
  587.     ip.eventPtr = eventPtr;
  588.     ip.winPtr = winPtr;
  589.     ip.nextHandler = NULL;
  590.     ip.nextPtr = pendingPtr;
  591.     pendingPtr = &ip;
  592.     if (mask == 0) {
  593.     if ((eventPtr->type == SelectionClear)
  594.         || (eventPtr->type == SelectionRequest)
  595.         || (eventPtr->type == SelectionNotify)) {
  596.         TkSelEventProc((Tk_Window) winPtr, eventPtr);
  597.     } else if ((eventPtr->type == ClientMessage)
  598.         && (eventPtr->xclient.message_type ==
  599.             Tk_InternAtom((Tk_Window) winPtr, "WM_PROTOCOLS"))) {
  600.         TkWmProtocolEventProc(winPtr, eventPtr);
  601.     }
  602.     } else {
  603.     for (handlerPtr = winPtr->handlerList; handlerPtr != NULL; ) {
  604.         if ((handlerPtr->mask & mask) != 0) {
  605.         ip.nextHandler = handlerPtr->nextPtr;
  606.         (*(handlerPtr->proc))(handlerPtr->clientData, eventPtr);
  607.         handlerPtr = ip.nextHandler;
  608.         } else {
  609.         handlerPtr = handlerPtr->nextPtr;
  610.         }
  611.     }
  612.  
  613.     /*
  614.      * Pass the event to the "bind" command mechanism.  But, don't
  615.      * do this for SubstructureNotify events.  The "bind" command
  616.      * doesn't support them anyway, and it's easier to filter out
  617.      * these events here than in the lower-level procedures.
  618.      */
  619.  
  620.     if ((ip.winPtr != None) && (mask != SubstructureNotifyMask)) {
  621.         TkBindEventProc(winPtr, eventPtr);
  622.     }
  623.     }
  624.     pendingPtr = ip.nextPtr;
  625. }
  626.  
  627. /*
  628.  *--------------------------------------------------------------
  629.  *
  630.  * TkEventDeadWindow --
  631.  *
  632.  *    This procedure is invoked when it is determined that
  633.  *    a window is dead.  It cleans up event-related information
  634.  *    about the window.
  635.  *
  636.  * Results:
  637.  *    None.
  638.  *
  639.  * Side effects:
  640.  *    Various things get cleaned up and recycled.
  641.  *
  642.  *--------------------------------------------------------------
  643.  */
  644.  
  645. void
  646. TkEventDeadWindow(winPtr)
  647.     TkWindow *winPtr;        /* Information about the window
  648.                  * that is being deleted. */
  649. {
  650.     register TkEventHandler *handlerPtr;
  651.     register InProgress *ipPtr;
  652.  
  653.     /*
  654.      * While deleting all the handlers, be careful to check for
  655.      * Tk_HandleEvent being about to process one of the deleted
  656.      * handlers.  If it is, tell it to quit (all of the handlers
  657.      * are being deleted).
  658.      */
  659.  
  660.     while (winPtr->handlerList != NULL) {
  661.     handlerPtr = winPtr->handlerList;
  662.     winPtr->handlerList = handlerPtr->nextPtr;
  663.     for (ipPtr = pendingPtr; ipPtr != NULL; ipPtr = ipPtr->nextPtr) {
  664.         if (ipPtr->nextHandler == handlerPtr) {
  665.         ipPtr->nextHandler = NULL;
  666.         }
  667.         if (ipPtr->winPtr == winPtr) {
  668.         ipPtr->winPtr = None;
  669.         }
  670.     }
  671.     ckfree((char *) handlerPtr);
  672.     }
  673. }
  674.  
  675. /*
  676.  *----------------------------------------------------------------------
  677.  *
  678.  * TkCurrentTime --
  679.  *
  680.  *    Try to deduce the current time.  "Current time" means the time
  681.  *    of the event that led to the current code being executed, which
  682.  *    means the time in the most recently-nested invocation of
  683.  *    Tk_HandleEvent.
  684.  *
  685.  * Results:
  686.  *    The return value is the time from the current event, or
  687.  *    CurrentTime if there is no current event or if the current
  688.  *    event contains no time.
  689.  *
  690.  * Side effects:
  691.  *    None.
  692.  *
  693.  *----------------------------------------------------------------------
  694.  */
  695.  
  696. Time
  697. TkCurrentTime(dispPtr)
  698.     TkDisplay *dispPtr;        /* Display for which the time is desired. */
  699. {
  700.     register XEvent *eventPtr;
  701.  
  702.     if (pendingPtr == NULL) {
  703.     return dispPtr->lastEventTime;
  704.     }
  705.     eventPtr = pendingPtr->eventPtr;
  706.     switch (eventPtr->type) {
  707.     case ButtonPress:
  708.     case ButtonRelease:
  709.         return eventPtr->xbutton.time;
  710.     case KeyPress:
  711.     case KeyRelease:
  712.         return eventPtr->xkey.time;
  713.     case MotionNotify:
  714.         return eventPtr->xmotion.time;
  715.     case EnterNotify:
  716.     case LeaveNotify:
  717.         return eventPtr->xcrossing.time;
  718.     case PropertyNotify:
  719.         return eventPtr->xproperty.time;
  720.     }
  721.     return dispPtr->lastEventTime;
  722. }
  723.